<?php
// +----------------------------------------------------------------------
// | ZGUAN [ 致力于帮助更多的中小企业物联网转型 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2024 https://www.zguan.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ZGUAN 并不是自由软件，未经许可不能去掉ZGUAN 相关版权
// +----------------------------------------------------------------------
// | Author: ZGUAN Team <admin@zguan.cn>  0769-82282996  15899929162
// +----------------------------------------------------------------------
namespace app\common\repositories\property\users;

use think\facade\Db;
use think\facade\Session;
use app\common\services\CacheService;
use think\exception\ValidateException;
use app\common\repositories\BaseRepository;
use app\common\dao\property\users\PropertyUsersDao;
use app\common\repositories\users\UsersRepository;
use app\common\repositories\property\auth\PropertyAuthRoleRepository;
use app\common\repositories\property\auth\PropertyAuthRuleRepository;
use app\common\repositories\property\users\PropertyUsersLogRepository;
use app\common\repositories\property\auth\PropertyAuthAccessRepository;

/**
 * Class PropertyUsersRepository
 *
 * @mixin PropertyUsersDao
 */
class PropertyUsersRepository extends BaseRepository
{

    const SESSION_NAME = 'property_user_info';

    public function __construct(PropertyUsersDao $dao)
    {
        $this->dao = $dao;
    }

    public function getPropertyList(array $where, $page, $limit, int $propertyId = null)
    {
        $query = $this->dao->search($where, $propertyId);
        $count = $query->count();
        $list = $query->page($page, $limit)
            ->with([
                'userInfo' => function ($query) {
                    $query->field('id,account,username,mobile');
                    $query->bind(['username', 'account', 'mobile']);
                },
                'groupInfo' => function ($query) {
                    $query->bind(['full_group_name']);
                }
            ])
            ->order('id', 'desc')
            ->select();
        return compact('list', 'count');
    }


    public function addInfo(array $data, int $propertyId = 1, int $userId = 0)
    {
        return Db::transaction(function () use ($data, $propertyId, $userId) {
            /** @var UsersRepository $userRepository */
            $userRepository = app()->make(UsersRepository::class);
            $userInfo = $userRepository->getInfoByMobile($data['mobile']);
            if (!$userInfo) {
                $userdData['email'] = $data['email'];
                $userdData['mobile'] = $data['mobile'];
                $userdData['account'] = $data['account'];
                $userdData['username'] = $data['username'];
                $userdData['password'] = $data['password'];
                $userInfo = $userRepository->register($userdData);
            }
            $propertyUserdata['property_id'] = $propertyId;
            $propertyUserdata['user_id'] = $userInfo['id'];
            $propertyUserdata['remark'] = $data['remark'] ?? '';
            $propertyUserdata['number'] = $data['number'] ?? '';
            $propertyUserdata['group_id'] = $data['group_id'] ?? '';
            $propertyUserdata['avatar_url'] = $data['avatar_url'] ?? '';
            $propertyUserdata['guard_card'] = $data['guard_card'] ?? '';
            $propertyUserdata['guard_password'] = $data['guard_password'] ?? '';
            $info = $this->dao->create($propertyUserdata);
            $accessData = [];
            foreach ($data['role_ids'] as $k => $v) {
                $accessData[] = [
                    'user_id' => $info['user_id'],
                    'property_id' => $propertyId,
                    'role_id' => $v
                ];
            }
            if ($accessData) {
                /** @var PropertyAuthAccessRepository $accessRepository */
                $accessRepository = app()->make(PropertyAuthAccessRepository::class);
                $accessRepository->insertAll($accessData);
            }
            /** @var PropertyUsersLogRepository $repository */
            $repository = app()->make(PropertyUsersLogRepository::class);
            $repository->addInfo($propertyId, $userId, 'PROPERTY.USERS.ADD', $data);
            return $info;
        });
    }


    public function editInfo($info, array $data, int $userId = 0)
    {
        return Db::transaction(function () use ($data, $info, $userId) {
            if ($info['userInfo']['account'] != $data['account']) {
                $userdData['account'] = $data['account'];
            }
            if ($info['userInfo']['mobile'] != $data['mobile']) {
                $userdData['mobile'] = $data['mobile'];
            }
            if ($info['userInfo']['username'] != $data['username']) {
                $userdData['username'] = $data['username'];
            }
            if ($info['userInfo']['email'] != $data['email']) {
                $userdData['email'] = $data['email'];
            }
            $userdData['password'] = $data['password'];
            /** @var UsersRepository $userRepository */
            $userRepository = app()->make(UsersRepository::class);
            $userRes = $userRepository->propertyDditInfo($info['user_id'], $userdData);

            if ($info['number'] != $data['number']) {
                $propertyUserdata['number'] = $data['number'] ?? '';
            }
            if ($info['group_id'] != $data['group_id']) {
                $propertyUserdata['group_id'] = $data['group_id'] ?? '';
            }
            $propertyUserdata['avatar_url'] = $data['avatar_url'] ?? '';
            if ($info['guard_card'] != $data['guard_card']) {
                $propertyUserdata['guard_card'] = $data['guard_card'] ?? '';
            }
            if ($info['guard_password'] != $data['guard_password']) {
                $propertyUserdata['guard_password'] = $data['guard_password'] ?? '';
            }
            $propertyUserdata['remark'] = $data['remark'] ?? '';
            $propertyUserRes = $this->dao->update($info['id'], $propertyUserdata);

            /** @var PropertyUsersLogRepository $repository */
            $repository = app()->make(PropertyUsersLogRepository::class);
            $repository->addInfo($info['property_id'], $userId, 'PROPERTY.USERS.EDIT', $data);
            return ($userRes || $propertyUserRes);
        });
    }

    public function batchDelete(array $ids, int $userId = 0)
    {
        $list = $this->dao->selectWhere([
            ['id', 'in', $ids]
        ]);
        if ($list) {
            foreach ($list as $k => $v) {
                $this->deleteInfo($v, $userId);
            }
            return $list;
        }
        return [];
    }

    public function deleteInfo($info, int $userId = 0)
    {
        /** @var PropertyUsersLogRepository $repository */
        $repository = app()->make(PropertyUsersLogRepository::class);
        $repository->addInfo($info['property_id'], $userId, 'PROPERTY.USERS.DEL', $info);
        $this->dao->delete($info['id']);
    }


    public function getDetail(int $id)
    {
        return $this->dao->getSearch(['id' => $id])
            ->with([
                'userInfo' => function ($query) {
                    $query->field('id,account,username,mobile,email');
                    $query->bind(['username', 'account', 'mobile', 'email']);
                },
                'groupInfo' => function ($query) {
                    $query->bind(['full_group_name']);
                }
            ])
            ->find();
    }

    public function getPropertyUserInfo()
    {
        return Session::get(self::SESSION_NAME);
    }

    public function getPropertyUId()
    {
        return $this->getPropertyUserInfo()['id'] ?? 0;
    }

    public function getUserId()
    {
        return $this->getPropertyUserInfo()['user_id'] ?? 0;
    }

    public function getPropertyId()
    {
        return $this->getPropertyUserInfo()['property_id'] ?? 0;
    }


    /**
     *
     * @return mixed|string
     *
     * @author Amos
     * 2024-01-06 22:23
     */
    public function getPropertyUserToken()
    {
        return $this->getPropertyUserInfo()['session_id'] ?? '';
    }

    public function isLogin()
    {
        return Session::has(self::SESSION_NAME);
    }

    /**
     * 管理员登录
     * @param $account
     * @param $password
     * @return \app\common\model\BaseModel|array|mixed|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     *
     * @author Amos
     * 2024-06-26 21:19
     */
    public function login($account, $password)
    {
        /**
         * @var UsersRepository $usersRepository
         */
        $usersRepository = app()->make(UsersRepository::class);
        $usersInfo = $usersRepository->getInfoByAccount($account);
        if (empty($usersInfo)) {
            throw new ValidateException('账号不存在或密码错误');
        }
        if (!$usersRepository->passwordVerify($password, $usersInfo['password'])) {
            throw new ValidateException('账号不存在或密码错误');
        }
        $propertyUserInfo = $this->getSearch(['user_id' => $usersInfo['id']])
            ->append(['user_info'])
            ->find();
        if (!$propertyUserInfo) {
            throw new ValidateException('账号不存在或权限不足');
        }
        if ($propertyUserInfo['is_show'] != 1) {
            throw new ValidateException('账号已被禁止登陆');
        }
        event('property.login', $propertyUserInfo);
        return $propertyUserInfo;
    }

    /**
     * 设置session信息
     * @param array $info 管理员信息
     * @return void
     *
     * @author Amos
     * 2024-01-07 09:23
     */
    public function setSessionInfo($info)
    {
        CacheService::create($info['property_id'])->delete('property_user_menus_' . $info['id']);
        CacheService::create($info['property_id'])->delete('property_user_rules_' . $info['id']);
        Session::set(self::SESSION_NAME, $info);
    }


    /**
     * 清除session信息
     * @return void
     *
     * @author Amos
     * 2024-01-07 13:42
     */
    public function clearSessionInfo()
    {
        CacheService::create($this->getPropertyId())->delete('property_user_menus_' . $this->getPropertyUId());
        CacheService::create($this->getPropertyId())->delete('property_user_rules_' . $this->getPropertyUId());
        Session::delete(self::SESSION_NAME);
    }


    /**
     * 获取侧边菜单
     * @return mixed
     *
     * @author Amos
     * 2024-01-07 15:44
     */
    public function getMenus()
    {
        $propertyUserInfo = $this->getPropertyUserInfo();
        $data = CacheService::create($propertyUserInfo['property_id'])->remember('property_user_menus_' . $propertyUserInfo['id'], function () use ($propertyUserInfo) {
            /**
             * @var PropertyAuthRuleRepository $repository
             */
            $repository = app()->make(PropertyAuthRuleRepository::class);
            $res = $repository->getUserMenus($propertyUserInfo);
            if ($res) {
                $res = $res->toArray();
            }
            $res = arr_level_sort($res, 2);
            $menus = $this->generateLayuiAdminMenu($res);
            $homeInfo = [
                'title' => '驾驶舱',
                'href' => (string)url('propertyIndexWelcome')
            ];
            $logoInfo = [
                'title' => '众冠物业管理后台',
                'image' => '',
                'href' => ''
            ];
            return [
                'homeInfo' => $homeInfo,
                'logoInfo' => $logoInfo,
                'menuInfo' => $menus
            ];
        }, 1);

        return $data;
    }

    /**
     * 生成layuiadmin菜单
     * @param $rules
     * @return array
     *
     * @author Amos
     * 2024-01-07 15:51
     */
    public function generateLayuiAdminMenu($rules)
    {
        $arr = [];
        foreach ($rules as $k => $v) {
            $arr2 = [
                'title' => $v['name'],
                'icon' => $v['icon'] ?? 'layui-icon-more-vertical',
                'target' => '_self'
            ];
            $arr2['href'] = $v['rule_url'] ? ltrim((string)url($v['rule_url']), '/') : '';
            if (isset($v[$v['id']]) && $v[$v['id']]) {
                $arr2['child'] = $this->generateLayuiAdminMenu($v[$v['id']]);
            }
            $arr[] = $arr2;
        }
        return $arr;
    }

    /**
     *  检测权限
     * @param $url
     * @return bool
     *
     * @author Amos
     * 2024-01-07 15:51
     */
    public function checkAuth($url)
    {
        $url = strtolower($url);
        $propertyUserInfo = $this->getPropertyUserInfo();
        if (empty($propertyUserInfo)) {
            return false;
        }
        ## 主管理员不验证权限
        if ($propertyUserInfo['is_main'] == 1 && $propertyUserInfo['is_show'] == 1) {
            return true;
        }
        $rules = CacheService::create($propertyUserInfo['property_id'])->remember('property_user_rules_' . $propertyUserInfo['id'], function () use ($propertyUserInfo) {
            /** @var PropertyAuthAccessRepository $accessRepository */
            $accessRepository = app()->make(PropertyAuthAccessRepository::class);
            $roleIds = $accessRepository->getSearch([])
                ->where('property_uid', $propertyUserInfo['id'])
                ->column('role_id');

            /** @var PropertyAuthRoleRepository $repository */
            $roleRepository = app()->make(PropertyAuthRoleRepository::class);

            $ruleIds = $roleRepository->getSearch([])
                ->where('property_id', $propertyUserInfo['property_id'])
                ->where('id', 'in', $roleIds)
                ->column('rules');
            $ruleIds = implode(',', $ruleIds);

            /**@var PropertyAuthRuleRepository $repository */
            $repository = app()->make(PropertyAuthRuleRepository::class);
            $rules = $repository->getRules(explode(',', $ruleIds));
            foreach ($rules as $k => $v) {
                $rules[$k] = strtolower($v);
            }
            return $rules;
        });
        if (in_array($url, $rules)) {
            return true;
        }
        return false;
    }

    public function getCascaderData(?int $propertyId = null, array $where = [])
    {
        $list = $this->dao->search($where, $propertyId)
            ->append(['username'])
            ->field('user_id')
            ->select()->toArray();
        foreach ($list as $k => $v) {
            $v['label'] = $v['username'];
            $v['value'] = $v['user_id'];
            unset($v['user_id']);
            unset($v['username']);
            $list[$k] = $v;
        }
        return $list;
    }
}